package tyt.android.bigplanettracks.tracks.writer;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import tyt.android.bigplanettracks.BigPlanet;
import tyt.android.bigplanettracks.maps.storage.SQLLocalStorage;
import tyt.android.bigplanettracks.tracks.TrackTabViewActivity;
import tyt.android.bigplanettracks.tracks.db.TrackDBAdapter;

import android.database.Cursor;
import android.location.Location;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

/**
 * @author taiyuchen, TYTung
 * @version 0.1
 */
public class GpxTrackWriter {
	private ArrayList<Location> locationList = null;
	private GpxFile gpxFile = null;
	private long trackID=0;
	private Handler trackListViewHandler=null;
	public static final int EXPORT_SUCCESS=1;
	public static final int EXPORT_FAIL=0;
	public static final int UPLOAD_SUCCESS=3;
	public static final int UPLOAD_FAIL=2;
	public static final int UPLOAD_FAIL_DUE_TO_TIMESTAMP_ERROR=4;
	
	private static final String UPLOAD_SUCCESS_TEXT = "LoginSucceededGpxSuccess";
	private static final String UPLOAD_TIMESTAMP_ERROR_TEXT = "GpxTimeStampError";
	
	/** Added by pengfei */
	private boolean toTuding = false;
	
	class myThread extends Thread {
		
		public void run() {
			
			Message m = null;
			if (trackID > 0) {
//				Log.i("Message", "Pick NO."+trackID+" DB record to export to the GPX File");
				try{
					//Retrive the track's attributes from Sqlite
					Cursor myCursor = BigPlanet.DBAdapter.getTrack(trackID);
					String trackName = myCursor.getString(myCursor.getColumnIndexOrThrow(TrackDBAdapter.FIELD_name));
					String trackDescription = myCursor.getString(myCursor.getColumnIndexOrThrow(TrackDBAdapter.FIELD_description));
					myCursor.close();
					if (trackName.equals(""))
						trackName = "NewTrack";
					
					locationList = new ArrayList<Location>();
					myCursor = BigPlanet.DBAdapter.getTrackPoints(trackID);
					for (int i=0; i < myCursor.getCount(); i++) {
						double latitude = myCursor.getDouble(myCursor.getColumnIndexOrThrow(TrackDBAdapter.FIELD_latitude));
						double longitude = myCursor.getDouble(myCursor.getColumnIndexOrThrow(TrackDBAdapter.FIELD_longitude)); 
						String strGMTTime = myCursor.getString(myCursor.getColumnIndexOrThrow(TrackDBAdapter.FIELD_time));
						double altitude = myCursor.getDouble(myCursor.getColumnIndexOrThrow(TrackDBAdapter.FIELD_altitude)); 
						
						Location location = new Location("");
						location.setLatitude(latitude);
						location.setLongitude(longitude);
						location.setAltitude(altitude);
						TrackDBAdapter.setGMTTimeString(location, strGMTTime);
						locationList.add(location);
						myCursor.moveToNext();
					}
					myCursor.close();
					
					// Need to check the capacity of the SD card before generating the GPX file
					
					// Generate the GPX File
					System.out.println("------------");
					Log.i("Message", "Generate GPX File...");
					gpxFile = new GpxFile(trackName, trackDescription);
					for (Location location: locationList) {
						gpxFile.saveLocation(location);
					}
					gpxFile.closeFile();
					Log.i("Message", "Finish...the GPX file exists in the directory: "+SQLLocalStorage.TRACK_PATH+"export/");
					System.out.println("------------");
					
					/** Added by pengfei */
					if (toTuding) {
						Map<String, String> params = new HashMap<String, String>();
						params.put("do", "loadgpx");
						params.put("username", BigPlanet.tudingUsername);
						params.put("password", BigPlanet.tudingPassword);
						//params.put("gpxfile", gpxFile.getFullFileName());
						
						Map<String, File> files = new HashMap<String, File>();
						files.put("gpxfile", gpxFile.getFileHandler());
						
						String postUrl = "http://www.tuding.org/android_upload.php";
						
						// Post to tuding
						String rc = postToTuding(postUrl, params, files);

						// @TODO: Fix the status judgment process
						// By pengfei
						if (rc.contains(UPLOAD_TIMESTAMP_ERROR_TEXT)) {
                            Log.i("Message", "Failed to upload gpx file to Tuding due to timestamp error");
							
							//sent message back to TrackListViewAvtivity handler
							String obj = "Fail!";
							m = trackListViewHandler.obtainMessage(UPLOAD_FAIL_DUE_TO_TIMESTAMP_ERROR, 0, 1, obj.toString());
							if(trackListViewHandler != null)
								trackListViewHandler.sendMessage(m);
							else
								throw new Error("trackListViewHandler is Null");	

						} else if (!rc.contains(UPLOAD_SUCCESS_TEXT)) {
							Log.i("Message", "Failed to upload gpx file to Tuding");
							
							//sent message back to TrackListViewAvtivity handler
							String obj = "Fail!";
							m = trackListViewHandler.obtainMessage(UPLOAD_FAIL, 0, 1, obj.toString());
							if(trackListViewHandler != null)
								trackListViewHandler.sendMessage(m);
							else
								throw new Error("trackListViewHandler is Null");
							
						} else {
							//sent message back to TrackListViewAvtivity handler
							String obj = "Success!";
							m = trackListViewHandler.obtainMessage(UPLOAD_SUCCESS, 1, 1, obj);
							
							if (trackListViewHandler != null)
								trackListViewHandler.sendMessage(m);
							else
								throw new Error("trackListViewHandler is Null");
						}
					} else {
					
						//sent message back to TrackListViewAvtivity handler
						String obj = "Success!";
						m = trackListViewHandler.obtainMessage(EXPORT_SUCCESS, 1, 1, obj);

						if (trackListViewHandler != null)
							trackListViewHandler.sendMessage(m);
						else
							throw new Error("trackListViewHandler is Null");
					}
					
				} catch(Exception e) {
					//sent message back to TrackListViewAvtivity handler
					String obj = "Fail!";
					m = trackListViewHandler.obtainMessage(EXPORT_FAIL, 0, 1, obj.toString());
					if(trackListViewHandler != null)
						trackListViewHandler.sendMessage(m);
					else
						throw new Error("trackListViewHandler is Null");
					e.printStackTrace();
					
				} finally {
					TrackTabViewActivity.myTrackExportDialog.dismiss();
				}
			} else {
				//sent message back to TrackListViewAvtivity handler
				TrackTabViewActivity.myTrackExportDialog.dismiss();
				String obj = "Fail!";
					m = trackListViewHandler.obtainMessage(EXPORT_FAIL, 0, 1, obj.toString());
					if(trackListViewHandler != null)
						trackListViewHandler.sendMessage(m);
					else
						throw new Error("trackListViewHandler is Null");
				Log.e("GpxTrackWriter", "myTrackDBAdapter == null or trackID <= 0");
			}
		}// end of run
	}
	
	public void setHandler(Handler handler) {
		this.trackListViewHandler = handler;
	}
	
	public void setTrackID(long trackID) {
		this.trackID = trackID;
	}
	
	public void setUpLoadtoTuding() {
	    this.toTuding = true;
	}
	
	public void saveToFile() {
//		Log.i("Message", "Start GpxFile Export Thread");
		myThread exportThread = new myThread();
		exportThread.setName("Export Thread");
		exportThread.start();
	}
	
	/**
	* Copyed from internet by pengfei
	* @param actionUrl
	* @param params
	* @param files
	* @return
	* @throws IOException
	*/
	public static String postToTuding(String actionUrl, Map<String, String> params, 
	    Map<String, File> files) throws IOException { 

		String BOUNDARY = java.util.UUID.randomUUID().toString();
		String PREFIX = "--" , LINEND = "\r\n";
		String MULTIPART_FROM_DATA = "multipart/form-data"; 
		String CHARSET = "UTF-8";

		URL uri = new URL(actionUrl); 
		HttpURLConnection conn = (HttpURLConnection) uri.openConnection(); 
		conn.setReadTimeout(5 * 1000);
		conn.setDoInput(true);
		conn.setDoOutput(true); 
		conn.setUseCaches(false); 
		conn.setRequestMethod("POST"); 
		conn.setRequestProperty("connection", "keep-alive"); 
		conn.setRequestProperty("Charsert", "UTF-8"); 
		conn.setRequestProperty("Content-Type", MULTIPART_FROM_DATA + ";boundary=" + BOUNDARY); 

		// Params
		StringBuilder sb = new StringBuilder(); 
		for (Map.Entry<String, String> entry : params.entrySet()) { 
			sb.append(PREFIX); 
			sb.append(BOUNDARY); 
			sb.append(LINEND); 
			sb.append("Content-Disposition: form-data; name=\"" + entry.getKey() + "\"" + LINEND);
			sb.append("Content-Type: text/plain; charset=" + CHARSET+LINEND);
			sb.append("Content-Transfer-Encoding: 8bit" + LINEND);
			sb.append(LINEND);
			sb.append(entry.getValue()); 
			sb.append(LINEND); 
		} 

		DataOutputStream outStream = new DataOutputStream(conn.getOutputStream()); 
		outStream.write(sb.toString().getBytes()); 

		// Files
		if(files!=null){
			int i = 0;
			for (Map.Entry<String, File> file: files.entrySet()) { 
				StringBuilder sb1 = new StringBuilder(); 
				sb1.append(PREFIX); 
				sb1.append(BOUNDARY); 
				sb1.append(LINEND); 
				//sb1.append("Content-Disposition: form-data; name=\"gpxfile"+(i++)+"\"; filename=\""+file.getKey()+"\""+LINEND);
				sb1.append("Content-Disposition: form-data; name=\"gpxfile"+"\"; filename=\""+file.getKey()+"\""+LINEND);
				sb1.append("Content-Type: application/octet-stream; charset="+CHARSET+LINEND);
				sb1.append(LINEND);
				outStream.write(sb1.toString().getBytes()); 

				InputStream is = new FileInputStream(file.getValue());
				byte[] buffer = new byte[1024]; 
				int len = 0; 
				while ((len = is.read(buffer)) != -1) { 
					outStream.write(buffer, 0, len); 
				}

				is.close(); 
				outStream.write(LINEND.getBytes()); 
			} 
		}

		// End of request
		byte[] end_data = (PREFIX + BOUNDARY + PREFIX + LINEND).getBytes(); 
		outStream.write(end_data); 
		outStream.flush(); 

		// get response code
		int res = conn.getResponseCode(); 
		InputStream in = null;
		StringBuilder sb2 = new StringBuilder(); 
		if (res == 200) {
			in = conn.getInputStream(); 
			int ch; 

			while ((ch = in.read()) != -1) { 
				sb2.append((char) ch); 
			} 
		}

		// Return input stream
		return sb2 == null ? null : sb2.toString(); 
	}

//	private boolean upLoadToTuding(GpxFile file) {
//		
//		HttpURLConnection connection = null;
//		
//		try {
//			
//			String tuding = "http://www.tuding.org/gmap_trace.php?";
//			
//			 // Post请求的url，与get不同的是不需要带参数
//	        URL postUrl = new URL(tuding);
//	        // 打开连接
//	        connection = (HttpURLConnection) postUrl
//	                .openConnection();
//	        // Output to the connection. Default is
//	        // false, set to true because post
//	        // method must write something to the
//	        // connection
//	        // 设置是否向connection输出，因为这个是post请求，参数要放在
//	        // http正文内，因此需要设为true
//	        connection.setDoOutput(true);
//	        // Read from the connection. Default is true.
//	        connection.setDoInput(true);
//	        // Set the post method. Default is GET
//	        connection.setRequestMethod("POST");
//	        // Post cannot use caches
//	        // Post 请求不能使用缓存
//	        connection.setUseCaches(false);
//	        // This method takes effects to
//	        // every instances of this class.
//	        // URLConnection.setFollowRedirects是static函数，作用于所有的URLConnection对象。
//	        // connection.setFollowRedirects(true);
//
//	        // This methods only
//	        // takes effacts to this
//	        // instance.
//	        // URLConnection.setInstanceFollowRedirects是成员函数，仅作用于当前函数
//	        connection.setInstanceFollowRedirects(true);
//	        // Set the content type to urlencoded,
//	        // because we will write
//	        // some URL-encoded content to the
//	        // connection. Settings above must be set before connect!
//	        // 配置本次连接的Content-type，配置为application/x-www-form-urlencoded的
//	        // 意思是正文是urlencoded编码过的form参数，下面我们可以看到我们对正文内容使用URLEncoder.encode
//	        // 进行编码
//	        connection.setRequestProperty("Content-Type",
//	                "application/x-www-form-urlencoded");
//	        // 连接，从postUrl.openConnection()至此的配置必须要在connect之前完成，
//	        // 要注意的是connection.getOutputStream会隐含的进行connect。
//	        connection.connect();
//	        DataOutputStream out = new DataOutputStream(connection
//	                .getOutputStream());
//	        // The URL-encoded contend
//	        // 正文，正文内容其实跟get的URL中'?'后的参数字符串一致
//	        String content = "do=" + URLEncoder.encode("loadgpx", "utf-8");
//	        content += "username=" + URLEncoder.encode("pengfeidaxia", "utf-8");
//	        content += "&password=" + URLEncoder.encode("83658365", "utf-8");
//	        content += "&gpxfile=" + URLEncoder.encode(file.getFullFileName(), "utf-8");
//	        // DataOutputStream.writeBytes将字符串中的16位的unicode字符以8位的字符形式写道流里面
//	        out.writeBytes(content);
//
//	        out.flush();
//	        out.close(); // flush and close
//	        /*
//			URL u = new URL(tuding);
//			connection = (HttpURLConnection) u.openConnection();
//			connection.setRequestMethod("GET");
//			connection.setReadTimeout(BaseLoader.CONNECTION_TIMEOUT);
//			connection.setConnectTimeout(BaseLoader.CONNECTION_TIMEOUT);
//			connection.connect();*/
//	        BufferedReader reader = new BufferedReader(new InputStreamReader(
//	        		connection.getInputStream()));
//	        reader.close();
//	        
//			int responseCode = connection.getResponseCode();
//			if (responseCode == HttpURLConnection.HTTP_OK) {
//				
//				connection.disconnect();
//				
//				Log.i("Tuding connection succeeded", tuding + " "+connection.getResponseMessage()+" " + connection.getResponseCode());
//				return true;
//			}
//		} catch(SocketTimeoutException e) {
//			e.printStackTrace();
//			System.out.println("timeout");
//		} catch (Exception e) {
//			Log.i("loading failed: exception", e.getMessage());
//			e.printStackTrace();
//		} finally {
//			connection.disconnect();
//		}
//		
//	    return false;
//	}
	
}
